import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor


def prepare_data():
    tr = datasets.FashionMNIST(root='data', train=True, download=True, transform=ToTensor())
    te = datasets.FashionMNIST(root='data', train=False, download=True, transform=ToTensor())

    batch_size = 64
    tr_loader = DataLoader(tr, batch_size=batch_size)
    te_loader = DataLoader(te, batch_size=batch_size)

    for x, y in te_loader:
        print(f'shape of x [n, c, h, w]: {x.shape}')
        print(f'shape of y {y.shape} {y.dtype}')
        break


class NeuralNetwork(nn.Module):
    def __init__(self):
        super(NeuralNetwork, self).__init__()
        self.flatten = nn.Flatten()
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(28 * 28, 512),
            nn.ReLU(),
            nn.Linear(512, 512),
            nn.ReLU(),
            nn.Linear(512, 10)
        )

    def forward(self, x):
        x = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits


def get_device():
    device = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'
    return device


device = get_device()


def create_model():
    print(f'device is {device}')
    return NeuralNetwork().to(device)


def optimize_model(net):
    loss_fn = nn.CrossEntropyLoss()
    optimizer = torch.optim.SGD(net.parameters(), lr=1e-3)


def train(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)
    model.train()
    for batch, (x, y) in enumerate(dataloader):
        x, y = x.to(device)


def main():
    # prepare_data()
    net = create_model()
    optimize_model(net)


if __name__ == '__main__':
    main()
